package com.zhaosc.mybatis.shared.table;

import java.lang.reflect.Field;
import java.util.List;

import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.scripting.xmltags.DynamicSqlSource;
import org.apache.ibatis.scripting.xmltags.ForEachSqlNode;
import org.apache.ibatis.scripting.xmltags.MixedSqlNode;
import org.apache.ibatis.scripting.xmltags.SqlNode;
import org.apache.ibatis.scripting.xmltags.StaticTextSqlNode;
import org.apache.ibatis.session.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.Lists;

public class DynamicSqlSourceHandler implements ISqlSourceHandler {

	private static Logger logger = LoggerFactory.getLogger(DynamicSqlSourceHandler.class);

	@Override
	public List<MySqlSource> handle(Configuration configuration, SqlSource sqlSource, String mapperId, String sql,
			TableShared tableShared, Class<?> parameterType) {

		String tableName = tableShared.tableName();
		int tableNum = tableShared.tableNum();

		List<MySqlSource> mySqlSourceList = Lists.newArrayList();
		try {
			Field rootSqlNodeField = sqlSource.getClass().getDeclaredField("rootSqlNode");
			rootSqlNodeField.setAccessible(true);
			SqlNode sqlNode = (SqlNode) rootSqlNodeField.get(sqlSource);

			MixedSqlNode mixedSqlNode = (MixedSqlNode) sqlNode;

			Field contentsField = mixedSqlNode.getClass().getDeclaredField("contents");
			contentsField.setAccessible(true);

			List<SqlNode> contents = (List<SqlNode>) contentsField.get(mixedSqlNode);

			for (int i = 0; i < tableNum; i++) {

				List<SqlNode> contentsNew = Lists.newArrayList();
				for (SqlNode sqlNodeT : contents) {

					if (sqlNodeT instanceof StaticTextSqlNode) {
						StaticTextSqlNode textSqlNode = (StaticTextSqlNode) sqlNodeT;
						Field textField = textSqlNode.getClass().getDeclaredField("text");
						textField.setAccessible(true);
						String sqlText = (String) textField.get(textSqlNode);
						String newSql = sqlText.replace(tableName, tableName + "_" + i);
						StaticTextSqlNode textSqlNodeNew = new StaticTextSqlNode(newSql);
						contentsNew.add(textSqlNodeNew);
					} else if (sqlNodeT instanceof ForEachSqlNode) {
						ForEachSqlNode forEachSqlNode = (ForEachSqlNode) sqlNodeT;

						Class<?> forEachSqlNodeClazz = forEachSqlNode.getClass();
						Field openField = forEachSqlNodeClazz.getDeclaredField("open");
						openField.setAccessible(true);
						String open = (String) openField.get(forEachSqlNode);

						Field closeField = forEachSqlNodeClazz.getDeclaredField("close");
						closeField.setAccessible(true);
						String close = (String) closeField.get(forEachSqlNode);

						Field separatorField = forEachSqlNodeClazz.getDeclaredField("separator");
						separatorField.setAccessible(true);
						String separator = (String) separatorField.get(forEachSqlNode);

						Field itemField = forEachSqlNodeClazz.getDeclaredField("item");
						itemField.setAccessible(true);
						String item = (String) itemField.get(forEachSqlNode);
						// 45

						Field indexField = forEachSqlNodeClazz.getDeclaredField("index");
						indexField.setAccessible(true);
						String index = (String) indexField.get(forEachSqlNode);

						Field collectionExpressionField = forEachSqlNodeClazz.getDeclaredField("collectionExpression");
						collectionExpressionField.setAccessible(true);
						String collectionExpression = (String) collectionExpressionField.get(forEachSqlNode);

						Field forContentsField = forEachSqlNode.getClass().getDeclaredField("contents");
						forContentsField.setAccessible(true);
						SqlNode forSqlNode = (SqlNode) forContentsField.get(forEachSqlNode);
						SqlNode forSqlNodeNew = null;
						if (forSqlNode instanceof MixedSqlNode) {
							MixedSqlNode forMixedSqlNode = (MixedSqlNode) forSqlNode;

							Field forMixContentsField = forMixedSqlNode.getClass().getDeclaredField("contents");
							forMixContentsField.setAccessible(true);
							List<SqlNode> forContents = (List<SqlNode>) forMixContentsField.get(forMixedSqlNode);
							List<SqlNode> forContentsNew = Lists.newArrayList();
							for (SqlNode forSqlNodeT : forContents) {
								if (forSqlNodeT instanceof StaticTextSqlNode) {
									StaticTextSqlNode textSqlNode = (StaticTextSqlNode) forSqlNodeT;
									Field textField = textSqlNode.getClass().getDeclaredField("text");
									textField.setAccessible(true);
									String sqlText = (String) textField.get(textSqlNode);
									if (sqlText.contains(tableName)) {
										String newSql = sqlText.replace(tableName, tableName + "_" + i);
										StaticTextSqlNode textSqlNodeNew = new StaticTextSqlNode(newSql);
										forContentsNew.add(textSqlNodeNew);
									} else {
										forContentsNew.add(forSqlNodeT);
									}

								} else {
									forContentsNew.add(forSqlNodeT);
								}

							}
							forSqlNodeNew = new MixedSqlNode(forContentsNew);

							ForEachSqlNode forEachSqlNodeNew = new ForEachSqlNode(configuration, forSqlNodeNew,
									collectionExpression, index, item, open, close, separator);
							contentsNew.add(forEachSqlNodeNew);

						} else {
							contentsNew.add(sqlNodeT);
						}

					} else {
						contentsNew.add(sqlNodeT);
					}
				}

				String myMapperId = mapperId.concat("-").concat(i + "");
				SqlNode rootSqlNode = new MixedSqlNode(contentsNew);
				SqlSource sqlSourceNew = new DynamicSqlSource(configuration, rootSqlNode);
				MySqlSource mySqlSource = MySqlSource.builder().sqlSource(sqlSourceNew).mapperId(myMapperId).build();
				mySqlSourceList.add(mySqlSource);
			}
		} catch (Exception e) {

			logger.error("", e);
		}

		return mySqlSourceList;

	}

}
